package org.thanos.iot.service.user;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.thanos.iot.controller.user.UserVo;
import org.thanos.iot.dao.user.SysUserDao;
import org.thanos.iot.dao.user.SysUserRoleDao;
import org.thanos.iot.entity.user.SysUser;
import org.thanos.iot.entity.user.SysUserRole;
import org.thanos.iot.service.role.RoleService;
import org.thanos.iot.util.response.CommonPage;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private SysUserDao sysUserDao;

    @Autowired
    private SysUserRoleDao sysUserRoleDao;

    @Autowired
    private RoleService roleService;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void addUser(String loginId, String password, String name, String telephone, String email, Integer roleId) {
        Assert.isTrue(StringUtils.isNotBlank(loginId), "loginId must not be null");
        Assert.isTrue(StringUtils.isNotBlank(password), "password must not be null");
        Assert.isTrue(StringUtils.isNotBlank(name), "name must not be null");
        Assert.isTrue(StringUtils.isNotBlank(telephone), "telephone must not be null");
        Assert.isTrue(StringUtils.isNotBlank(email), "email must not be null");
        Assert.notNull(roleId, "roleId must not be null");
        SysUser user = sysUserDao.findByLoginId(loginId);
        Assert.isNull(user, "user is exists");
        user = new SysUser();
        user.setLoginId(loginId);
        user.setPassword(password);
        user.setName(name);
        user.setTelephone(telephone);
        user.setEmail(email);
        user.setStatus(BigDecimal.ZERO.intValue());
        Date now = Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC));
        user.setCreateTime(now);
        user.setUpdateTime(now);
        user.setVersion(BigDecimal.ZERO.intValue());
        sysUserDao.save(user);
        SysUserRole userRole = new SysUserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(roleId);
        userRoleMapper.insertSelective(userRole);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void modifyUser(Integer id, String name, String telephone, String email, Integer roleId) {
        SysUser user = userMapper.selectByPrimaryKey(id);
        Assert.isTrue(Optional.ofNullable(user).isPresent(), "user is not exists");
        user.setName(name);
        user.setTelephone(telephone);
        user.setEmail(email);
        user.setUpdateTime(Timestamp.valueOf(LocalDateTime.now()));
        userMapper.updateByPrimaryKeySelective(user);
        Optional.ofNullable(roleId).ifPresent(role -> userRoleMapper.updateByUserId(id, role));
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void modifyUserPassword(Integer userId, String password) {
        SysUser user = userMapper.selectByPrimaryKey(userId);
        Assert.isTrue(Optional.ofNullable(user).isPresent(), "user is not exists");
        user.setPassword(password);
        userMapper.updateByPrimaryKeySelective(user);
    }

    @Override
    public UserVo discoverUser(Integer userId) {
        SysUser user = userMapper.selectByPrimaryKey(userId);
        if (Objects.isNull(user)) {
            return null;
        }
        UserVo userVo = new UserVo();
        userVo.setId(user.getId());
        userVo.setLoginId(user.getLoginId());
        userVo.setPassword(user.getPassword());
        userVo.setName(user.getName());
        userVo.setTelephone(user.getTelephone());
        userVo.setEmail(user.getEmail());
        Optional.ofNullable(userRoleMapper.selectByUserId(userId)).ifPresent(userRole -> userVo.setRoleVo(roleService.discoverOne(userRole.getRoleId())));
        return userVo;
    }

    @Override
    public boolean discoverUserByLoginId(String loginId, Integer id) {
        SysUser commonUser = userMapper.selectByLoginId(loginId, id);
        return Optional.ofNullable(commonUser).isPresent();
    }

    @Override
    public CommonPage<UserVo> discoverUsers(String name, Integer pageNum, Integer pageSize) {
        Page<SysUser> page = PageHelper.startPage(pageNum, pageSize, true);
        userMapper.queryByParams(name);
        PageInfo<SysUser> info = PageInfo.of(page.getResult());
        List<UserVo> results = page.getResult().stream().map(user -> {
            UserVo userVo = new UserVo();
            userVo.setId(user.getId());
            userVo.setLoginId(user.getLoginId());
            userVo.setPassword(user.getPassword());
            userVo.setName(user.getName());
            userVo.setTelephone(user.getTelephone());
            userVo.setEmail(user.getEmail());
            userVo.setCreateTime(user.getCreateTime().getTime());
            userVo.setStatus(user.getStatus());
            Optional.ofNullable(userRoleMapper.selectByUserId(user.getId())).ifPresent(userRole -> userVo.setRoleVo(roleService.discoverOne(userRole.getRoleId())));
            return userVo;
        }).collect(Collectors.toList());
        return CommonPage.of(info.getTotal(), results);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deleteUser(Integer userId) {
        SysUser user = userMapper.selectByPrimaryKey(userId);
        Assert.isTrue(Optional.ofNullable(user).isPresent(), "can not find user");
        user.setStatus(Boolean.FALSE);
        userMapper.updateByPrimaryKeySelective(user);
        userRoleMapper.deleteByPrimaryKey(userId);
    }
}
